import {createCipheriv, createDecipheriv, randomBytes, scryptSync} from 'crypto';
import {IEncryptor} from '../types';

/**
 * 基础加密器
 */
abstract class BaseEncryptor implements IEncryptor {
    protected readonly key: Buffer;
    protected readonly algorithm: string;
    protected readonly ivLength: number;

    /**
     * 构造函数
     * @param password 密码
     * @param algorithm 加密算法
     * @param ivLength 初始化向量长度
     */
    constructor(password: string, algorithm: string, ivLength: number) {
        // 使用同步版本的 scrypt 生成密钥
        const salt = randomBytes(16);
        this.key = scryptSync(Buffer.from(password), salt, 32);
        this.algorithm = algorithm;
        this.ivLength = ivLength;
    }

    encrypt(data: string): string {
        try {
            // 生成随机初始化向量
            const iv = randomBytes(this.ivLength);

            // 创建加密器
            const cipher = createCipheriv(this.algorithm, this.key, iv);

            // 加密数据
            let encrypted = cipher.update(data, 'utf8', 'hex');
            encrypted += cipher.final('hex');

            // 将 IV 附加到加密数据前面
            return iv.toString('hex') + ':' + encrypted;
        } catch (error) {
            throw new Error(`Encryption failed: ${(error as Error).message}`);
        }
    }

    decrypt(data: string): string {
        try {
            // 分离 IV 和加密数据
            const [ivHex, encryptedHex] = data.split(':');
            if (!ivHex || !encryptedHex) {
                throw new Error('Invalid encrypted data format');
            }

            // 转换 IV 和加密数据
            const iv = Buffer.from(ivHex, 'hex');

            // 创建解密器
            const decipher = createDecipheriv(this.algorithm, this.key, iv);

            // 解密数据
            let decrypted = decipher.update(encryptedHex, 'hex', 'utf8');
            decrypted += decipher.final('utf8');

            return decrypted;
        } catch (error) {
            throw new Error(`Decryption failed: ${(error as Error).message}`);
        }
    }
}

/**
 * AES-256-CBC 加密器
 */
export class AesEncryptor extends BaseEncryptor {
    constructor(password: string) {
        super(password, 'aes-256-cbc', 16);
    }
}

/**
 * AES-256-GCM 加密器（带认证）
 */
export class AesGcmEncryptor implements IEncryptor {
    private readonly key: Buffer;
    private static readonly algorithm = 'aes-256-gcm';
    private static readonly ivLength = 12;

    constructor(password: string) {
        // 使用同步版本的 scrypt 生成密钥
        const salt = randomBytes(16);
        this.key = scryptSync(Buffer.from(password), salt, 32);
    }

    encrypt(data: string): string {
        try {
            // 生成随机初始化向量
            const iv = randomBytes(AesGcmEncryptor.ivLength);

            // 创建加密器
            const cipher = createCipheriv(AesGcmEncryptor.algorithm, this.key, iv);

            // 加密数据
            let encrypted = cipher.update(data, 'utf8', 'hex');
            encrypted += cipher.final('hex');

            // 获取认证标签
            const authTag = cipher.getAuthTag();

            // 将 IV 和认证标签附加到加密数据
            return iv.toString('hex') + ':' + authTag.toString('hex') + ':' + encrypted;
        } catch (error) {
            throw new Error(`Encryption failed: ${(error as Error).message}`);
        }
    }

    decrypt(data: string): string {
        try {
            // 分离 IV、认证标签和加密数据
            const [ivHex, authTagHex, encryptedHex] = data.split(':');
            if (!ivHex || !authTagHex || !encryptedHex) {
                throw new Error('Invalid encrypted data format');
            }

            // 转换 IV、认证标签和加密数据
            const iv = Buffer.from(ivHex, 'hex');
            const authTag = Buffer.from(authTagHex, 'hex');

            // 创建解密器
            const decipher = createDecipheriv(AesGcmEncryptor.algorithm, this.key, iv);
            decipher.setAuthTag(authTag);

            // 解密数据
            let decrypted = decipher.update(encryptedHex, 'hex', 'utf8');
            decrypted += decipher.final('utf8');

            return decrypted;
        } catch (error) {
            throw new Error(`Decryption failed: ${(error as Error).message}`);
        }
    }
}

/**
 * Base64编码器
 */
export class Base64Encryptor implements IEncryptor {
    encrypt(data: string): string {
        return Buffer.from(data, 'utf8').toString('base64');
    }

    decrypt(data: string): string {
        return Buffer.from(data, 'base64').toString('utf8');
    }
}

/**
 * 创建加密器
 * @param type 加密类型
 * @param password 密码
 */
export function createEncryptor(
    type: 'aes-cbc' | 'aes-gcm' | 'base64',
    password: string = ''
): IEncryptor {
    switch (type) {
        case 'aes-cbc':
            return new AesEncryptor(password);
        case 'aes-gcm':
            return new AesGcmEncryptor(password);
        case 'base64':
            return new Base64Encryptor();
        default:
            throw new Error(`Unsupported encryption type: ${type}`);
    }
}
